﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Xml;

namespace Common.XmlHandle
{
    public class XmlContact : IDisposable
    {
        private static XmlDocument xdoc = null;
        private string xmlPath = null;
        private XmlNode root = null;
        static ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();

        public string XmlPath { get => xmlPath; set => xmlPath = value; }
        public static XmlDocument Xdoc { get => xdoc; set => xdoc = value; }
        public XmlNode Root { get => root; set => root = value; }

        public XmlContact(string path)
        {
            XmlPath = path;
            try
            {
                Xdoc = new XmlDocument();
                Xdoc.Load(path);
                Root = Xdoc.SelectSingleNode("Contacts");
            }
            catch (DirectoryNotFoundException)
            {
                Directory.CreateDirectory(path.Substring(0, path.LastIndexOf(@"\")));
                XmlDeclaration dec = Xdoc.CreateXmlDeclaration("1.0", "utf-8", null);
                Xdoc.AppendChild(dec);
                Xdoc.AppendChild(Xdoc.CreateElement("Contacts"));
                Root = Xdoc.SelectSingleNode("Contacts");
                Xdoc.Save(path);
                if (Root == null)
                {
                    throw new Exception(XmlPath + " 路径下的XML文档结构错误。");
                }
            }
            catch (FileNotFoundException)
            {
                XmlDeclaration dec = Xdoc.CreateXmlDeclaration("1.0", "utf-8", null);
                Xdoc.AppendChild(dec);
                Xdoc.AppendChild(Xdoc.CreateElement("Contacts"));
                Root = Xdoc.SelectSingleNode("Contacts");
                Xdoc.Save(path);
            }
            catch (XmlException)
            {
                Xdoc = new XmlDocument();
                XmlDeclaration dec = Xdoc.CreateXmlDeclaration("1.0", "utf-8", null);
                Xdoc.AppendChild(dec);
                Xdoc.AppendChild(Xdoc.CreateElement("Contacts"));
                Root = Xdoc.SelectSingleNode("Contacts");
                Xdoc.Save(path);
            }
            catch
            {
                throw;
            }
        }

        public List<ClassContact> GetAll()
        {
            lockSlim.EnterReadLock();
            //xdoc.Load(xmlPath);
            //root = xdoc.SelectSingleNode("Contacts");
            List<ClassContact> contacts = new List<ClassContact>(80);
            foreach(XmlNode xNode in Root.ChildNodes)
            {
                Guid guid = new Guid((xNode as XmlElement).GetAttribute("Brigade"));
                if (guid == Guid.Empty) continue;
                foreach(XmlNode node in xNode.ChildNodes)
                {
                    ClassContact contact = new ClassContact();
                    contact.Brigade = guid;
                    XmlElement element = node as XmlElement;
                    contact.Name = element.GetAttribute("Name");
                    contact.Phone = element.GetAttribute("Phone");
                    contacts.Add(contact);
                }
            }
            lockSlim.ExitReadLock();
            return contacts;
        }

        /// <summary>
        /// 编码为socket传输字符串
        /// 分隔符："♠","♥","♣","♦"
        /// </summary>
        /// <returns></returns>
        public List<string> Coding2SocketString()
        {
            List<string> b = new List<string>(20);
            List<ClassContact> list = GetAll();
            List<Guid> guids = new List<Guid>(10);
            StringBuilder builder = new StringBuilder(1024 - 40);
            int index = 0;
            foreach(ClassContact contact in list)
            {
                string cell = null;
                if (guids.IndexOf(contact.Brigade) < 0)
                {
                    cell = contact.Brigade + "♠" + contact.Name + "♣" + contact.Phone + "♥";
                    guids.Add(contact.Brigade);
                }
                else
                {
                    cell = contact.Name + "♣" + contact.Phone + "♥";
                }
                int cellLenght = cell.Length * 8;
                if (index + cellLenght < 984)
                {
                    builder.Append(cell);
                    index = index + cellLenght;
                }
                else
                {
                    b.Add(builder.ToString());
                    builder.Clear();
                    index = 0;
                    cell = contact.Brigade + "♠" + contact.Name + "♣" + contact.Phone + "♥";
                    cellLenght = cell.Length * 8;
                    builder.Append(cell);
                    index = index + cellLenght;
                }
            }
            return b;
        }

        public void DecodingSocketString(string str)
        {

        }

        public ClassContact GetContactByName(string brigade, string name)
        {
            lockSlim.EnterReadLock();
            //xdoc.Load(xmlPath);
            //root = xdoc.SelectSingleNode("Contacts");
            XmlNodeList nodeList = Root.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                XmlElement ele = (XmlElement)node;
                if (ele.GetAttribute("Brigade").Equals(brigade))
                {
                    XmlNodeList nods = node.ChildNodes;
                    foreach (XmlNode nod in nods)
                    {
                        XmlElement e = (XmlElement)nod;
                        if (e.GetAttribute("Name").Equals(name))
                        {
                            ClassContact b = new ClassContact();
                            b.Brigade = new Guid(brigade);
                            b.Phone = e.GetAttribute("Phone");
                            b.Name = name;
                            lockSlim.ExitReadLock();
                            return b;
                        }
                    }
                    break;
                }
            }
            lockSlim.ExitReadLock();
            return null;
        }

        public ClassContact GetContactByPhone(string brigade, string phone)
        {
            lockSlim.EnterReadLock();
            //xdoc.Load(xmlPath);
            //root = xdoc.SelectSingleNode("Contacts");
            XmlNodeList nodeList = Root.ChildNodes;

            foreach (XmlNode node in nodeList)
            {
                XmlElement ele = (XmlElement)node;
                if (ele.GetAttribute("Brigade").Equals(brigade))
                {
                    XmlNodeList nods = node.ChildNodes;
                    foreach (XmlNode nod in nods)
                    {
                        XmlElement e = (XmlElement)nod;
                        if (e.GetAttribute("Phone").Equals(phone))
                        {
                            ClassContact b = new ClassContact();
                            b.Brigade = new Guid(brigade);
                            b.Name = e.GetAttribute("Name");
                            b.Phone = e.GetAttribute("Phone");
                            lockSlim.ExitReadLock();
                            return b;
                        }
                    }
                    break;
                }
            }
            lockSlim.ExitReadLock();
            return null;
        }

        public long GetFileSize()
        {
            FileInfo f = new FileInfo(XmlPath);
            return f.Length;
        }

        public void AddContact(ClassContact contact)
        {
            if(contact.Brigade == Guid.Empty)
            {
                return;
            }
            try
            {
                string phone = string.Empty;
                lockSlim.EnterWriteLock();
                Xdoc.Load(XmlPath);
                Root = Xdoc.SelectSingleNode("Contacts");
                XmlNodeList nodeList = Root.ChildNodes;
                int countBri = nodeList.Count;
                int indexBri = -1;
                int indexCon = -1;
                for(int i = 0; i < countBri; i++)
                {
                    XmlElement xBri = nodeList[i] as XmlElement;
                    if(xBri.GetAttribute("Brigade") == contact.Brigade.ToString())
                    {
                        indexBri = i;
                        break;
                    }
                }
                if(indexBri < 0)
                {
                    Root.AppendChild(Contact2Node(contact));
                    Xdoc.Save(XmlPath);
                }
                else
                {
                    int countCon = nodeList[indexBri].ChildNodes.Count;
                    for (int j = 0; j < countCon; j++)
                    {
                        XmlElement xCon = nodeList[indexBri].ChildNodes[j] as XmlElement;
                        if (xCon.GetAttribute("Name") == contact.Name)
                        {
                            string p = xCon.GetAttribute("Phone");
                            if (p != contact.Phone)
                            {
                                if(contact.Phone.IndexOf(",") > 0)
                                {
                                    (nodeList[indexBri].ChildNodes[j] as XmlElement).SetAttribute("Phone", contact.Phone.Substring(0, contact.Phone.IndexOf(",")));
                                }
                                else
                                {
                                    (nodeList[indexBri].ChildNodes[j] as XmlElement).SetAttribute("Phone", contact.Phone);
                                }
                                Xdoc.Save(XmlPath);
                            }
                            indexCon = j;
                            break;
                        }
                    }
                    if(indexCon < 0)
                    {
                        nodeList[indexBri].AppendChild(Contact2Ele(contact));
                        Xdoc.Save(XmlPath);
                    }
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                if (lockSlim.IsWriteLockHeld)
                {
                    lockSlim.ExitWriteLock();
                }
            }
        }

        public void RemoveContact(ClassContact classContact)
        {
            lockSlim.EnterWriteLock();
            //xdoc.Load(xmlPath);
            //root = xdoc.SelectSingleNode("Contacts");
            foreach (XmlNode xmlNode in Root)
            {
                XmlElement xmlElement = xmlNode as XmlElement;
                if (xmlElement.GetAttribute("Brigade").Equals(classContact.Brigade.ToString()))
                {
                    XmlNodeList xmlNodeList = xmlNode.ChildNodes;
                    foreach(XmlNode node in xmlNodeList)
                    {
                        XmlElement element = node as XmlElement;
                        string name = element.GetAttribute("Name");
                        string phone = element.GetAttribute("Phone");
                        if(name == classContact.Name & phone == classContact.Phone)
                        {
                            node.ParentNode.RemoveChild(node);
                            Xdoc.Save(XmlPath);
                            lockSlim.ExitWriteLock();
                            return;
                        }
                    }
                }
            }
            lockSlim.ExitWriteLock();
        }

        public string GetContact(Guid brigade, string name)
        {
            lockSlim.EnterReadLock();
            //xdoc.Load(xmlPath);
            //root = xdoc.SelectSingleNode("Contacts");
            XmlNodeList nodeList = Root.ChildNodes;
            if (nodeList != null)
            {
                foreach (XmlNode node in nodeList)
                {
                    XmlElement xele = (XmlElement)node;
                    if (brigade.Equals(new Guid(xele.GetAttribute("Brigade"))))
                    {
                        XmlNodeList nList = node.ChildNodes;
                        if (nList != null)
                        {
                            foreach (XmlNode no in nList)
                            {
                                XmlElement ele = (XmlElement)no;
                                if (name.Equals(ele.GetAttribute("Name")))
                                {
                                    lockSlim.ExitReadLock();
                                    return ele.GetAttribute("Phone");
                                }
                            }
                            lockSlim.ExitReadLock();
                            return null;
                        }
                        else
                        {
                            lockSlim.ExitReadLock();
                            return null;
                        }
                    }
                }
            }
            lockSlim.ExitReadLock();
            return null;
        }

        private XmlElement Contact2Ele(ClassContact contact)
        {
            XmlElement ele = Xdoc.CreateElement("Person");
            ele.SetAttribute("Name", contact.Name);
            ele.SetAttribute("Phone", contact.Phone);
            return ele;
        }

        private XmlElement Contact2Node(ClassContact contact)
        {
            XmlElement node = Xdoc.CreateElement("Contact");
            node.SetAttribute("Brigade", contact.Brigade.ToString());
            XmlElement ele = Xdoc.CreateElement("Person");
            ele.SetAttribute("Name", contact.Name);
            ele.SetAttribute("Phone", contact.Phone);
            node.AppendChild(ele);
            return node;
        }

        public void Dispose()
        {
            Dispose();
            GC.SuppressFinalize(this);
        }
    }
}
